﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ActionerBase.cs" company="DissingNelleman">
//   
// All rights reserved. </copyright>
// <summary>
//   The actioner base.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ServiceLibrary.Actioners
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using NHibernate;
    using NHibernate.Criterion;

    using ServiceLibrary.Actioners.Base;
    using ServiceLibrary.Services.Dto;
    using ServiceLibrary.Services.Queries;

    using User = ServiceLibrary.Models.Domain.User;

    /// <summary>
    /// The actioner base.
    /// </summary>
    public class ActionerBase
    {
        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ActionerBase"/> class.
        /// </summary>
        /// <param name="session">
        /// The session.
        /// </param>
        /// <param name="activeUser">
        /// The active user.
        /// </param>
        public ActionerBase(ISession session, User activeUser)
        {
            this.ActiveUser = activeUser;
            this.Session = session;
            this.Log = new LogEntryActioner(this.Session, activeUser);
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the active user.
        /// </summary>
        protected User ActiveUser { get; set; }

        /// <summary>
        /// Gets or sets the log.
        /// </summary>
        protected LogEntryActioner Log { get; set; }

        /// <summary>
        /// Gets or sets the session.
        /// </summary>
        protected ISession Session { get; set; }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The apply default criterias.
        /// </summary>
        /// <param name="settings">
        /// The settings.
        /// </param>
        /// <param name="query">
        /// The query.
        /// </param>
        /// <typeparam name="T">
        /// The type of the object being queried.
        /// </typeparam>
        public void ApplyDefaultCriterias<T>(SearchSettings settings, IQueryOver<T, T> query)
        {
            if (settings != null)
            {
                if (!settings.IDEquals.Equals(Guid.Empty))
                {
                    query.RootCriteria.Add(Restrictions.Eq("ID", settings.IDEquals));
                }

                if (settings.CreationDateFrom != null)
                {
                    if (typeof(T) == typeof(Models.Base.LogEntry))
                    {
                        query.RootCriteria.Add(Restrictions.Ge("Timestamp", settings.CreationDateFrom));
                    }
                    else
                    {
                        query.RootCriteria.Add(Restrictions.Ge("CreatedDateTime", settings.CreationDateFrom));
                    }
                    
                }

                if (settings.CreationDateTo != null)
                {
                    if (typeof(T) == typeof(Models.Base.LogEntry))
                    {
                        query.RootCriteria.Add(Restrictions.Le("Timestamp", settings.CreationDateTo));
                    }
                    else
                    {
                        query.RootCriteria.Add(Restrictions.Le("CreatedDateTime", settings.CreationDateTo));
                    }
                    
                }

                // TODO: Implement this
                // if (!settings.Id_Not_Equal.Equals(Guid.Empty))
                // {
                // criteria.Add(Expression.("ID", settings.Id_Not_Equal));
                // }
                if (settings.IDIsIn != null && settings.IDIsIn.Any())
                {
                    query.RootCriteria.Add(Restrictions.InG("ID", settings.IDIsIn));
                }
            }
        }

        /// <summary>
        /// The apply default search field criterias reports search.
        /// </summary>
        /// <param name="defaultFields">
        /// The default fields.
        /// </param>
        /// <param name="query">
        /// The query.
        /// </param>
        /// <typeparam name="T">
        /// The type of the object being queried.
        /// </typeparam>
        public void ApplyDefaultSearchFieldCriteriasReportsSearch<T>(
            DefaultSearchFields defaultFields, IQueryOver<T, T> query)
        {
            if (defaultFields != null)
            {
                if (defaultFields.HappenedAfter.HasValue)
                {
                    query.RootCriteria.Add(Restrictions.Ge("TimeOfActivity", defaultFields.HappenedAfter.Value));
                }

                if (defaultFields.HappenedBefore.HasValue)
                {
                    query.RootCriteria.Add(Restrictions.Le("TimeOfActivity", defaultFields.HappenedBefore.Value));
                }

                if ((defaultFields.OwnerProjects ?? new List<Guid>()).Any())
                {
                    query.RootCriteria.CreateAlias("OwnerProjects", "op")
                         .Add(Restrictions.In("op.ID", defaultFields.OwnerProjects));
                }
            }
        }

        /// <summary>
        /// The apply skip and take.
        /// </summary>
        /// <param name="settings">
        /// The settings.
        /// </param>
        /// <param name="query">
        /// The query.
        /// </param>
        /// <typeparam name="T">
        /// The type of the object being queried.
        /// </typeparam>
        /// <returns>
        /// The list resulting from the applying skip and take.
        /// </returns>
        public IList<T> ApplySkipAndTake<T>(SearchSettings settings, IQueryOver<T, T> query)
        {
            if (settings != null && settings.Skip != null && settings.Take != null && settings.Take > 0)
            {
                return query.Skip((int)settings.Skip).Take((int)settings.Take).List();
            }

            return query.List();
        }

        /// <summary>
        /// The apply skip and take.
        /// </summary>
        /// <param name="settings">
        /// The settings.
        /// </param>
        /// <param name="query">
        /// The query.
        /// </param>
        /// <typeparam name="T">
        /// The type of the object being queried.
        /// </typeparam>
        /// <returns>
        /// The list resulting from the applying skip and take.
        /// </returns>
        public IEnumerable<T> ApplySkipAndTake<T>(SearchSettings settings, IEnumerable<T> query)
        {
            if (settings != null && settings.Skip != null && settings.Take != null && settings.Take > 0)
            {
                return query.Skip((int)settings.Skip).Take((int)settings.Take).ToList();
            }
            
            return query.ToList();
        }

        #endregion
    }
}